/*
 * Copyright (c) 2009 DeledImporter
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 *
 * * Neither the name of 'Pyro Games' nor the names of its contributors 
 *   may be used to endorse or promote products derived from this software 
 *   without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package net.pyrogames.deled.math;

/**
 * Convenient representation of any 3D coordinate or direction
 * from a dxs file.
 * 
 * @author Nicholas Woodfield
 *
 */
public class DXSVector3f {
	/** x value of this vector */
	public float x;
	/** y value of this vector */
	public float y;
	/** z value of this vector */
	public float z;
	/** id of this vector */
	public int vid;
	
	/**
	 * Default constructor, everything set to 0.
	 */
	public DXSVector3f(){
		x = y = z = vid = 0;
	}
	
	/**
	 * Set the x, y, z values and the id to 0
	 * 
	 * @param X
	 * 		x value of this vector
	 * @param Y
	 * 		y value of this vector
	 * @param Z
	 * 		z value of this vector
	 * @param VID
	 * 		id of this vector
	 */
	public DXSVector3f(float X, float Y, float Z){
		x = X;
		y = Y;
		z = Z;
		vid = 0;
	}
	
	/**
	 * Set the x, y, z values and the id
	 * 
	 * @param X
	 * 		x value of this vector
	 * @param Y
	 * 		y value of this vector
	 * @param Z
	 * 		z value of this vector
	 * @param VID
	 * 		id of this vector
	 */
	public DXSVector3f(float X, float Y, float Z, int VID){
		x = X;
		y = Y;
		z = Z;
		vid = VID;
	}
	
	/**
	 * Initialize a new vector with the values from the input.
	 * 
	 * @param v
	 * 		Input vector
	 */
	public DXSVector3f(DXSVector3f v){
		x = v.x;
		y = v.y;
		z = v.z;
		vid = v.vid;
	}
	
	/**
	 * Copy the values from the input vector
	 * 
	 * @param v
	 * 		Input vector
	 * @return
	 * 		Return this vector
	 */
	public DXSVector3f set(DXSVector3f v){
		x = v.x;
		y = v.y;
		z = v.z;
		vid = v.vid;
		return this;
	}
	
	/**
	 * Set x,y,z values from the specified float values
	 * 
	 * @param sX
	 * @param sY
	 * @param sZ
	 */
    public void set(float sX, float sY, float sZ){
    	x = sX;
    	y = sY;
    	z = sZ;
    }
	
	/**
	 * Apply the cross product with the input vector
	 * 
	 * @param v2
	 * 		Input vector
	 * @return
	 * 		a new vector
	 */
	public DXSVector3f cross(DXSVector3f v2){
        float resX = ((y * v2.z) - (z * v2.y)); 
        float resY = ((z * v2.x) - (x * v2.z));
        float resZ = ((x * v2.y) - (y * v2.x));
        return new DXSVector3f(resX,resY,resZ);
	}
	
	/**
	 * Subtract this vector from the input vector
	 * 
	 * @param v
	 * 		Input vector
	 * @return
	 * 		a new vector with the result
	 */
	public DXSVector3f subtract(DXSVector3f v){
		return new DXSVector3f(x-v.x, y-v.y, z-v.z);
	}
	
	/**
	 * Subtract this vector from the input vector,
	 * save the result in this vector.
	 * 
	 * @param v
	 * 		Input vector
	 * @return
	 * 		this vector
	 */
	public DXSVector3f subtractLocal(DXSVector3f v){
		x -= v.x;
		y -= v.y;
		z -= v.z;
		return this;
	}
	
	/**
	 * Add this vector with an input vector
	 * 
	 * @param v
	 * 		Input vector
	 * @return
	 * 		a new vector with the result
	 */
	public DXSVector3f add(DXSVector3f v){
		return new DXSVector3f(x+v.x, y+v.y, z+v.z);
	}
	
	/**
	 * Add this vector with an input vector,
	 * save result in this vector
	 * 
	 * @param v
	 * 		Input vector
	 * @return
	 * 		this vector
	 */
	public DXSVector3f addLocal(DXSVector3f v){
		x += v.x;
		y += v.y;
		z += v.z;
		return this;
	}
	
	/**
	 * Normalize this vector and save it in this vector
	 * 
	 * @return
	 * 		this vector
	 */
	public DXSVector3f normalizeLocal(){
        float length = length();
        if (length != 0) {
            return divideLocal(length);
        }
        return this;  
	}
	
	/**
	 * Normalize this vector and return a new vector
	 * 
	 * @return
	 * 		a new vector
	 */
	public DXSVector3f normalize(){
        float length = length();
        if (length != 0) {
            return divide(length);
        }
        return divide(1);  
	}
	
	/**
	 * Divide this vector by a scalar,
	 * and save the result in this vector
	 * 
	 * @param scalar
	 * 		float
	 * @return
	 * 		this vector
	 */
    public DXSVector3f divideLocal(float scalar) {
        scalar = 1f/scalar;
        x *= scalar;
        y *= scalar;
        z *= scalar;
        return this;
    }
    
    /**
     * Divide this vector by a scalar,
     * returns a new vector
     * 
     * @param scalar
     * 		float 
     * @return
     * 		a new vector
     */
    public DXSVector3f divide(float scalar) {
        scalar = 1f/scalar;
        return new DXSVector3f(x*scalar,y*scalar,z*scalar);
    }
    
    /**
     * Square of this vector's length
     * 
     * @return
     */
    public float lengthSquared() {
        return x * x + y * y + z * z;
    }
    
    /**
     * Length of this vector
     * 
     * @return
     */
    public float length(){
    	return (float) Math.sqrt(lengthSquared());
    }
    
    /**
     * Resets this vector to (0,0,0)
     */
    public void reset(){
    	x = y = z = 0;
    }
    
    /**
     * Multiplies all components by the specified scalar
     * 
     * @param m
     * 		Scalar float value
     * @return
     * 		This vector
     */
    public DXSVector3f multLocal(float m){
    	x *= m;
    	y *= m;
    	z *= m;
    	return this;
    }
    
    /**
     * Creates a new vector where its components are
     * multiplied by the specified scalar.
     * 
     * @param m
     * 		Scalar float value
     * @return
     * 		A new vector
     */
    public DXSVector3f mult(float m){
    	DXSVector3f toReturn = new DXSVector3f(x*m,y*m,z*m);
    	return toReturn;
    }
    
    @Override
    public String toString(){
    	return DXSVector3f.class.getName() + " [X=" + x + ", Y=" + y + ", Z=" + z + "]";
    }
 
}
